{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": [],
      "collapsed_sections": [
        "C-68gn27DW8M"
      ]
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "source": [
        "# (0) Install dependencies for golang."
      ],
      "metadata": {
        "id": "C-68gn27DW8M"
      }
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "rAn9fYboCwEL"
      },
      "outputs": [],
      "source": [
        "# (1.1) run this cell first time using python runtime\n",
        "!apt update\n",
        "!apt install golang-go\n",
        "!apt-get install libdw-dev\n",
        "%env GOPATH=/root/go\n",
        "# (1.2) then refresh, it will now use gophernotes. Skip to golang in later cells"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "#(1)Install BMF"
      ],
      "metadata": {
        "id": "ISczRD0avf5M"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!pip install BabitMF\n"
      ],
      "metadata": {
        "id": "KhlymhlIaJm_"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "#(2) Configure the environment variable to reference the BMF C library with go."
      ],
      "metadata": {
        "id": "RReEQfMkvtxP"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "! which bmf_env\n",
        "! cat /usr/local/bin/bmf_env\n",
        "! bmf_env"
      ],
      "metadata": {
        "id": "j-Lhe1lKaWE-"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "Copy and execute it in your terminal, in colab, we use %env:"
      ],
      "metadata": {
        "id": "Ntn_mXqZae6f"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "%env C_INCLUDE_PATH=/usr/local/lib/python3.10/dist-packages/bmf/include\n",
        "%env CPLUS_INCLUDE_PATH=/usr/local/lib/python3.10/dist-packages/bmf/include\n",
        "%env LIBRARY_PATH=/usr/local/cuda/lib64/stubs:/usr/local/lib/python3.10/dist-packages/bmf/lib\n",
        "%env LD_LIBRARY_PATH=/usr/local/nvidia/lib:/usr/local/nvidia/lib64:/usr/local/lib/python3.10/dist-packages/bmf/lib"
      ],
      "metadata": {
        "id": "OSijioHQab96"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "#(3) Download a sample transcoded video and mov from our assets (using Big Bunny as an example here)."
      ],
      "metadata": {
        "id": "ocbnv5sIakmX"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!wget https://github.com/BabitMF/bmf/releases/download/files/files.tar.gz\n",
        "!tar -zvxf files.tar.gz"
      ],
      "metadata": {
        "id": "sxrMv1I2te_I"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "# (4) Implement a simple transcoding function With BMF Go SDK"
      ],
      "metadata": {
        "id": "xsu0XSlvyTph"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "%%writefile /content/sync_mode.go\n",
        "package main\n",
        "import (\n",
        "  \"github.com/babitmf/bmf-gosdk/bmf\"\n",
        "  \"fmt\"\n",
        "  \"os\"\n",
        "\t\"time\"\n",
        ")\n",
        "func syncModeSerial() {\n",
        "\tdecoder, err0 := bmf.NewModuleFunctorBuiltin(\"c_ffmpeg_decoder\", map[string]interface{}{\n",
        "\t\t\"input_path\": \"./files/big_bunny_10s_30fps.mp4\",\n",
        "\t}, 0, 1)\n",
        "\tdefer decoder.Free()\n",
        "\tif decoder == nil {\n",
        "\t\t\tfmt.Printf(\"Load decoder module failed %v\\n\", err0)\n",
        "\t} else {\n",
        "\t\t\tfmt.Printf(\"Load decoder module successful\\n\")\n",
        "\t}\n",
        "\n",
        "\tencoder, err1 := bmf.NewModuleFunctorBuiltin(\"c_ffmpeg_encoder\", map[string]interface{}{\n",
        "\t\t\"output_path\": \"./output_sync_mode_serial.mp4\",\n",
        "\t}, 1, 0)\n",
        "\tdefer encoder.Free()\n",
        "\tif encoder == nil {\n",
        "\t\t\tfmt.Printf(\"Load encoder module failed %v\\n\", err1)\n",
        "\t} else {\n",
        "\t\t\tfmt.Printf(\"Load encoder module successful\\n\")\n",
        "\t}\n",
        "\n",
        "\tpass, err2 := bmf.NewModuleFunctorBuiltin(\"pass_through\", nil, 1, 1)\n",
        "\tdefer pass.Free()\n",
        "\tif pass == nil {\n",
        "\t\t\tfmt.Printf(\"Load pass_through module failed %v\\n\", err2)\n",
        "\t} else {\n",
        "\t\t\tfmt.Printf(\"Load pass_through module successful\\n\")\n",
        "\t}\n",
        "\tfmt.Println(\"Sync mode Serial\")\n",
        "\n",
        "\tfor {\n",
        "\t\t// do decoder module\n",
        "        is_done, err := decoder.Execute([]*bmf.Packet{}, true)\n",
        "        if is_done {\n",
        "\t\t\tfmt.Printf(\"Decode done\\n\")\n",
        "\n",
        "\t\t\t// EOF packet\n",
        "\t\t\tp_eof := bmf.GenerateEofPacket()\n",
        "\t\t\tpkts_eof := []*bmf.Packet{}\n",
        "\t\t\tpkts_eof = append(pkts_eof, p_eof)\n",
        "\t\t\tis_done_eof, err_eof := pass.Execute(pkts_eof, true)\n",
        "\t\t\tif is_done_eof {\n",
        "\t\t\t\t\tbreak\n",
        "\t\t\t}\n",
        "\t\t\tif err_eof != nil {\n",
        "\t\t\t\tfmt.Println(\"PassThrough EOF execute failed error : %v\\n\", err_eof)\n",
        "\t\t\t}\n",
        "\t\t\topkts_eof, err1_eof := pass.Fetch(0)\n",
        "\t\t\tif err1_eof != nil {\n",
        "\t\t\t\tfmt.Println(\"PassThrough EOF fetch failed error : %v\\n\", err1_eof)\n",
        "\t\t\t}\n",
        "\n",
        "\t\t\tfor i := 0; i < len(opkts_eof); i++ {\n",
        "\t\t\t\t_, err_enc_eof := encoder.Call([]*bmf.Packet{opkts_eof[i]})\n",
        "\t\t\t\tif err_enc_eof != nil {\n",
        "\t\t\t\t\tfmt.Printf(\"encoder EOF call failed! error : %v\\n\",err_enc_eof)\n",
        "\t\t\t\t}\n",
        "\t\t\t}\n",
        "\t\t\tbreak\n",
        "        }\n",
        "\n",
        "        if err != nil {\n",
        "\t\t\tfmt.Printf(\"decoder execute failed! error : %v\\n\", err)\n",
        "\t\t\tbreak\n",
        "        }\n",
        "\n",
        "        opkts_dec, err1 := decoder.Fetch(0)\n",
        "        if err1 != nil {\n",
        "\t\t\tfmt.Printf(\"decoder fetch failed!\\n, error : %v\", err1)\n",
        "            break\n",
        "        }\n",
        "\n",
        "\t\t// do pass_through module\n",
        "\t\tfor i := 0; i < len(opkts_dec); i++ {\n",
        "\t\t\tipkts_pass := []*bmf.Packet{}\n",
        "\t\t\tipkts_pass = append(ipkts_pass, opkts_dec[i])\n",
        "\t\t\t_, err2 := pass.Execute(ipkts_pass, true)\n",
        "\t\t\tif err2 != nil {\n",
        "\t\t\t\tfmt.Printf(\"Pass Through failed! %v\\n\", err2)\n",
        "\t\t\t\tbreak\n",
        "\t\t\t}\n",
        "\n",
        "\t\t\topkts_pass, err1 := pass.Fetch(0)\n",
        "\t\t\tif err1 != nil {\n",
        "\t\t\t\tfmt.Printf(\"Pass Through Fetch failed! error : %v\\n\", err1)\n",
        "\t\t\t\tbreak\n",
        "\t\t\t}\n",
        "\n",
        "\t\t\t// do encoder module\n",
        "\t\t\tfor i := 0; i < len(opkts_pass); i++ {\n",
        "\t\t\t\t_, err := encoder.Call([]*bmf.Packet{opkts_pass[i]})\n",
        "\t\t\t\tif err != nil {\n",
        "\t\t\t\t\tfmt.Printf(\"encoder call failed! error : %v\\n\", err)\n",
        "\t\t\t\t}\n",
        "\t\t\t}\n",
        "\n",
        "\t\t }\n",
        "\t}\n",
        "}\n",
        "\n",
        "func syncMode() {\n",
        "\tdone := false\n",
        "\tdecoder, err0 := bmf.NewModuleFunctorBuiltin(\"c_ffmpeg_decoder\", map[string]interface{}{\n",
        "\t\t\"input_path\": \"./files/big_bunny_10s_30fps.mp4\",\n",
        "\t}, 0, 1)\n",
        "\tif decoder == nil {\n",
        "\t\t\tfmt.Printf(\"Load decoder module failed %v\\n\", err0)\n",
        "\t} else {\n",
        "\t\t\tfmt.Printf(\"Load decoder module successful\\n\")\n",
        "\t}\n",
        "\n",
        "\tencoder, err1 := bmf.NewModuleFunctorBuiltin(\"c_ffmpeg_encoder\", map[string]interface{}{\n",
        "\t\t\"output_path\": \"./output_sync_mode.mp4\",\n",
        "\t}, 1, 0)\n",
        "\tif encoder == nil {\n",
        "\t\t\tfmt.Printf(\"Load encoder module failed %v\\n\", err1)\n",
        "\t} else {\n",
        "\t\t\tfmt.Printf(\"Load encoder module successful\\n\")\n",
        "\t}\n",
        "\n",
        "\tpass, err2 := bmf.NewModuleFunctorBuiltin(\"pass_through\", nil, 1, 1)\n",
        "\tif pass == nil {\n",
        "\t\t\tfmt.Printf(\"Load pass_through module failed %v\\n\", err2)\n",
        "\t} else {\n",
        "\t\t\tfmt.Printf(\"Load pass_through module successful\\n\")\n",
        "\t}\n",
        "\tpassChan := make(chan []*bmf.Packet, 10)\n",
        "\tencChan := make(chan []*bmf.Packet, 10)\n",
        "\tfmt.Println(\"Sync mode\")\n",
        "\t// PassThrough\n",
        "\tgo func() {\n",
        "\t\tfor opkts_dec := range passChan {\n",
        "\t\t\teofSet := false\n",
        "\n",
        "\t\t\t// do pass_through module\n",
        "\t\t\tfor i := 0; i < len(opkts_dec); i++ {\n",
        "\t\t\t\tipkts_pass := []*bmf.Packet{}\n",
        "\t\t\t\tipkts_pass = append(ipkts_pass, opkts_dec[i])\n",
        "\t\t\t\tif opkts_dec[i].Timestamp() == bmf.EOF {\n",
        "\t\t\t\t\teofSet = true\n",
        "\t\t\t\t}\n",
        "\t\t\t\t_, err2 := pass.Execute(ipkts_pass, true)\n",
        "\t\t\t\tif err2 != nil {\n",
        "\t\t\t\t\tfmt.Printf(\"Pass Through failed! %v\\n\", err2)\n",
        "\t\t\t\t\tbreak\n",
        "\t\t\t\t}\n",
        "\n",
        "\t\t\t\topkts_pass, err1 := pass.Fetch(0)\n",
        "\t\t\t\tif err1 != nil {\n",
        "\t\t\t\t\tfmt.Printf(\"Pass Through Fetch failed! error : %v\\n\", err1)\n",
        "\t\t\t\t\tbreak\n",
        "\t\t\t\t}\n",
        "\t\t\t\t// do encoder module\n",
        "\t\t\t\tfor i := 0; i < len(opkts_pass); i++ {\n",
        "\t\t\t\t\tencChan <- []*bmf.Packet{opkts_pass[i]}\n",
        "\t\t\t\t}\n",
        "\n",
        "\t\t\t}\n",
        "\n",
        "\t\t\tif eofSet {\n",
        "\t\t\t\tfmt.Println(\"pass done\")\n",
        "\t\t\t\tencChan <- []*bmf.Packet{bmf.GenerateEofPacket()}\n",
        "\t\t\t\tpass.Free()\n",
        "\t\t\t\tbreak\n",
        "\t\t\t}\n",
        "\t\t}\n",
        "\t}()\n",
        "\n",
        "\t\t// Encoder\n",
        "\tgo func() {\n",
        "\t\tfor opkts_pass := range encChan {\n",
        "\t\t\teofSet := false\n",
        "\n",
        "\t\t\t// do encoder module\n",
        "\t\t\tfor i := 0; i < len(opkts_pass); i++ {\n",
        "\t\t\t\t_, err := encoder.Call([]*bmf.Packet{opkts_pass[i]})\n",
        "\t\t\t\tif err != nil {\n",
        "\t\t\t\t\tfmt.Printf(\"encoder call failed! error : %v\\n\", err)\n",
        "\t\t\t\t\tbreak\n",
        "\t\t\t\t}\n",
        "\t\t\t\tif opkts_pass[i].Timestamp() == bmf.EOF {\n",
        "\t\t\t\t\teofSet = true\n",
        "\t\t\t\t}\n",
        "\t\t\t}\n",
        "\n",
        "\t\t\tif eofSet {\n",
        "\t\t\t\tfmt.Println(\"enc done\")\n",
        "\t\t\t\tencoder.Free()\n",
        "\t\t\t\tdone = true\n",
        "\t\t\t\tbreak\n",
        "\t\t\t}\n",
        "\t\t}\n",
        "\t}()\n",
        "\n",
        "\tfor {\n",
        "\t\t// do decoder module\n",
        "        is_done, err := decoder.Execute([]*bmf.Packet{}, true)\n",
        "        if is_done {\n",
        "\t\t\tfmt.Printf(\"Decode done\\n\")\n",
        "\n",
        "\t\t\t// EOF packet\n",
        "\t\t\tp_eof := bmf.GenerateEofPacket()\n",
        "\t\t\tpkts_eof := []*bmf.Packet{}\n",
        "\t\t\tpkts_eof = append(pkts_eof, p_eof)\n",
        "\t\t\tpassChan <- pkts_eof\n",
        "\t\t\tdecoder.Free()\n",
        "\t\t\tbreak\n",
        "        }\n",
        "\n",
        "        if err != nil {\n",
        "\t\t\tfmt.Printf(\"decoder execute failed! error : %v\\n\", err)\n",
        "\t\t\tbreak\n",
        "        }\n",
        "\n",
        "        opkts_dec, err1 := decoder.Fetch(0)\n",
        "        if err1 != nil {\n",
        "\t\t\tfmt.Printf(\"decoder fetch failed!\\n, error : %v\", err1)\n",
        "            break\n",
        "        }\n",
        "\n",
        "\t\t// do pass_through module\n",
        "\t\tfor i := 0; i < len(opkts_dec); i++ {\n",
        "\t\t\tipkts_pass := []*bmf.Packet{}\n",
        "\t\t\tipkts_pass = append(ipkts_pass, opkts_dec[i])\n",
        "\t\t\tpassChan <- ipkts_pass\n",
        "\t\t }\n",
        "\t}\n",
        "\n",
        "\tfor !done {\n",
        "\t\ttime.Sleep(100 * time.Millisecond)\n",
        "\t}\n",
        "\n",
        "}\n",
        "\n",
        "func main() {\n",
        "\tif os.Args[1] == \"syncMode\" {\n",
        "\t    syncMode()\n",
        "\t}\n",
        "\tif os.Args[1] == \"syncModeSerial\" {\n",
        "\t    syncModeSerial()\n",
        "\t}\n",
        "}"
      ],
      "metadata": {
        "id": "ajyppvwijzz0"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "#(6) Compile the code and call the bmf library through go."
      ],
      "metadata": {
        "id": "zaYzP-L6yanW"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!go mod init test\n",
        "!go mod tidy\n",
        "!go build sync_mode.go"
      ],
      "metadata": {
        "id": "ZLndmSNFkRar"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "!./sync_mode syncModeSerial"
      ],
      "metadata": {
        "id": "r53DymHJsuLb"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "!./sync_mode syncMode"
      ],
      "metadata": {
        "id": "9zCD4ArzI5dR"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "from IPython.display import HTML\n",
        "from base64 import b64encode\n",
        "\n",
        "def show_video(video_path, video_width = 800):\n",
        "  video_file = open(video_path, \"r+b\").read()\n",
        "  video_url = f\"data:video/mp4;base64,{b64encode(video_file).decode()}\"\n",
        "  return f\"\"\"\n",
        "  <video width={video_width} controls>\n",
        "    <source src=\"{video_url}\">\n",
        "  </video>\n",
        "  \"\"\"\n",
        "\n",
        "video_url1 = show_video('./files/big_bunny_10s_30fps.mp4')\n",
        "video_url2 = show_video('output_sync_mode_serial.mp4')\n",
        "video_url3 = show_video('output_sync_mode.mp4')\n",
        "\n",
        "html = video_url1 + video_url2 + video_url3\n",
        "HTML(html)"
      ],
      "metadata": {
        "id": "uuxERnkZmzxs"
      },
      "execution_count": null,
      "outputs": []
    }
  ]
}
